#include "custom_filter.h"

#include <regex>
#include <windows.h>
#include "file_filter.h"
#include "log.h"
#include "string_util.h"
#include "win_util.h"

namespace {
const BlockType DEFAULT_BLOCK_TYPE = {
    true, L"提示", L"检测到此应用未经测试，可能存在卡顿、部分软件功能不可用现象，是否允许运行?"};

bool IsProcessAssociateWith(std::wstring &product, const std::wstring &file, const AppInfo &app)
{
    for (auto item : app.productNameList) {
        if (FindIgnoreCase(product, item)) {
            return true;
        }
    }
    for (auto &item : app.fileNamePatternList) {
        if (std::regex_match(file, std::wregex(item, std::regex::icase))) {
            return true;
        }
    }
    return false;
}
}  // namespace

BlockType BlockTypeDetector::Detect(const ProcessInfo &process)
{
    std::shared_ptr<ProductInfo> info = GetProcessFileProductInfo(process.fileName);
    std::wstring productName;
    if (info != nullptr) {
        productName = info->productName;
    }
    std::wstring file = GetFileName(process.fileName);

    for (auto &app : blockAppList) {
        if (IsProcessAssociateWith(productName, file, app)) {
            auto iterator = blockTypes.find(app.tag);
            if (iterator != blockTypes.end()) {
                return iterator->second;
            }
        }
    }
    return DEFAULT_BLOCK_TYPE;
}

CustomFilter::CustomFilter() = default;

CustomFilter::CustomFilter(
    const std::vector<AppInfo> &blockAppList, const std::map<std::wstring, BlockType> &blockTypes)
{
    this->detector = std::make_unique<BlockTypeDetector>(blockAppList, blockTypes);
}

CustomFilter::~CustomFilter() = default;

bool CustomFilter::Handle(const ProcessInfo &process)
{
    LOG_DEBUG("user confirm.");
    std::wstring file = GetFileName(process.fileName);
    if (cache.Exist(file)) {
        return true;
    }
    auto type = DEFAULT_BLOCK_TYPE;
    if (detector != nullptr) {
        type = detector->Detect(process);
    }
    auto ret = BlockHandle(type, process);
    LOG_INFO("{} confirm result: {}", UnicodeToUtf8(process.fileName), ret);
    if (ret) {
        std::unique_lock<std::mutex> lock;
        cache.Set(file, process.fileName);
    }
    return ret;
}

void CustomFilter::Update()
{}

bool CustomFilter::BlockHandle(const BlockType &type, const ProcessInfo &process)
{
    auto messageBoxType = MB_YESNO;
    if (!type.enable) {
        messageBoxType = MB_OK;
    }
    auto ret = MessageBoxW(nullptr, type.content.c_str(), type.title.c_str(), messageBoxType);
    return ret == IDYES;
}
